#include "VulkanApplication.h"
#include <vector>
#include <iostream>

int main(int argc, char** argv)
{
    VulkanApplication app("c06_submitting", 1024, 768);
    if (!app.initialized())
    {
        printf("Failed to initialize VulkanApplication.\n");
        return 1;
    }

    // Create command pool
    VkCommandPoolCreateInfo poolInfo
    {
        VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
        nullptr,
        VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
        0  // queueFamilyIndex
    };
    VkCommandPool commandPool = nullptr;
    VkResult result = vkCreateCommandPool(app.getDevice(), &poolInfo, nullptr, &commandPool);
    if (result != VK_SUCCESS)
    {
        printf("Failed to create command pool.\n");
        return 1;
    }

    // Create command buffer
    VkCommandBufferAllocateInfo allocInfo
    {
        VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
        nullptr, commandPool,
        VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1
    };
    VkCommandBuffer commandBuffer = nullptr;
    result = vkAllocateCommandBuffers(app.getDevice(), &allocInfo, &commandBuffer);
    if (result != VK_SUCCESS)
    {
        printf("Failed to create command buffer.\n");
        return 1;
    }

    // Main loop
    VkFence waitFence = app.getOrCreateFence("CommandFence");
    VkSemaphore waitNextImage = app.getOrCreateSemaphore("WaitNextImage");
    VkSemaphore waitSubmission = app.getOrCreateSemaphore("WaitSubmission");

    VkQueue queue = nullptr;
    vkGetDeviceQueue(app.getDevice(), 0, 0, &queue);
    while (!app.shouldClose())
    {
        vkWaitForFences(app.getDevice(), 1, &waitFence, VK_TRUE, UINT64_MAX);
        vkResetFences(app.getDevice(), 1, &waitFence);

        uint32_t imageIndex = 0;
        result = vkAcquireNextImageKHR(app.getDevice(), app.getSwapchain(), UINT64_MAX,
                                       waitNextImage, VK_NULL_HANDLE, &imageIndex);
        switch (result)
        {
        case VK_SUCCESS:
            printf("Next image: %d\n", imageIndex); break;
        default:
            printf("Next image: %d (RESULT = %d)\n", imageIndex, result);
            app.setClosed(); break;
        }

        VkCommandBufferBeginInfo beginInfo
        {
            VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            nullptr, 0, nullptr
        };
        vkResetCommandBuffer(commandBuffer, 0);
        vkBeginCommandBuffer(commandBuffer, &beginInfo);
        // TODO
        vkEndCommandBuffer(commandBuffer);

        VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        VkSwapchainKHR swapChains[] = { app.getSwapchain() };

        VkSubmitInfo submitInfo
        {
            VK_STRUCTURE_TYPE_SUBMIT_INFO,
            nullptr,
            1, & waitNextImage,  // pWaitSemaphores
            &waitStageMask,      // pWaitDstStageMask
            1, &commandBuffer,
            1, &waitSubmission   // pSignalSemaphores
        };
        vkQueueSubmit(queue, 1, &submitInfo, waitFence);

        VkPresentInfoKHR presentInfo
        {
            VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
            nullptr,
            1, &waitSubmission,   // pWaitSemaphores
            1, swapChains,        // pSwapchains
            &imageIndex,          // pImageIndices
            nullptr
        };
        vkQueuePresentKHR(queue, &presentInfo);
        glfwPollEvents();
    }

    vkDestroyCommandPool(app.getDevice(), commandPool, nullptr);
    return 0;
}